package com.karrim.server.io.sql;

import com.karrim.server.io.sql.def.SQLLoader;
import com.karrim.server.io.sql.def.SQLLocator;
import com.karrim.server.io.sql.def.SQLStream;
import com.karrim.server.io.sql.util.Field;
import com.karrim.server.io.sql.util.Table;
import com.karrim.server.util.Util;
import com.karrim.server.util.array.DynamicList;
import com.karrim.server.util.array.def.Array;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author andrea.cantafio
 */
public abstract class AbstractSQLLoader<Connector extends SQLStream> implements SQLLoader<Connector> {

    public AbstractSQLLoader(Connector connector) {
        this.connector = connector;
    }

    public ResultSet load(final String sql) throws SQLException {
        return tryLoadLocated(connector, new SQLLocator() {
            @Override
            public String get() {
                return sql;
            }
        });
    }

    @Override
    public ResultSet load(Connector connectable) {

        throw new UnsupportedOperationException(Util.UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
    }

    @Override
    public ResultSet tryLoadLocated(Connector connectable, SQLLocator locable) throws SQLException {
        Connection connection = connectable.get();
        Statement s = null;
        try {
            s = connection.createStatement();
            return s.executeQuery(locable.get());
        } catch (SQLException sqle) {
            Logger.getLogger(AbstractSQLLoader.class.getName()).log(Level.SEVERE, sqle.toString());
            throw sqle;
        } finally {
            if (s != null) {
                s.closeOnCompletion();
            }
        }
    }

    protected Table getTableDefinition(ResultSetMetaData metaData) throws SQLException {
        int columnCount = metaData.getColumnCount();
        String table = metaData.getTableName(1);
        Table t = new Table(table);
        for (int i = 0; i < columnCount; i++) {
            String sql_type = metaData.getColumnTypeName(i + 1);
            switch (sql_type) {
                case "COUNTER":
                    sql_type = "LONG";
                    break;
                case "VARCHAR":
                    sql_type += "(" + metaData.getPrecision(i + 1) + ")";
                    break;
                case "LONGCHAR":
                    sql_type = "VARCHAR(1000)";
                    break;
            }
            Field f = new Field(metaData.getColumnLabel(i + 1), sql_type, metaData.isNullable(i + 1) == ResultSetMetaData.columnNullable);
            try {
                f.setJavaType(metaData.getColumnClassName(i + 1));
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(AccessLoader.class.getName()).log(Level.SEVERE, null, ex);
            }
            t.addField(f);
        }
        return t;
    }

    protected String[] getTableNames(final String sql) throws SQLException {
        return getTableNames(new SQLLocator() {
            @Override
            public String get() {
                return sql;
            }
        });
    }

    protected String[] getTableNames(SQLLocator locator) throws SQLException {
        ResultSet result = tryLoadLocated(connector, locator);
        Array<String> arr = new DynamicList<>();
        while (result.next()) {
            arr.add(result.getString(1));
        }
        return arr.toArray();
    }
    protected Connector connector;
}
